home *** CD-ROM | disk | FTP | other *** search
/ Best Tools for JAVA / Best Tools for JAVA.iso / JAVA_ALL / IDE / SUBARTIC / RELEASE.ZIP / sub_arctic / anim / animation_agent.java < prev    next >
Encoding:
Java Source  |  1996-10-04  |  13.2 KB  |  422 lines

  1. package sub_arctic.anim;
  2. import sub_arctic.input.*;
  3. import sub_arctic.lib.*;
  4.  
  5. import java.awt.Event;
  6. import java.util.Vector;
  7.  
  8. /**
  9.  * This is the dispatch agent which handles animation input events and 
  10.  * dispatches them to interface objects via the animatable input protocol 
  11.  * interface. Animation events are generated by a single instance of
  12.  * the anim_generator class that runs in its own thread.<p>
  13.  *
  14.  * @author Ian Smith
  15.  */
  16. public class animation_agent extends dispatch_agent {
  17.  
  18.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  19.  
  20.   /**
  21.    * This is the magic value for animation events.<p>
  22.    * 
  23.    * Editorial comment by Ian:<br>
  24.    *    Note that Event.MISC_EVENT is PRIVATE because AWT is too
  25.    *    stupid to let anyone do anything useful. Further, they
  26.    *    add constants to it to derive MISC_EVENT values (which 
  27.    *    is still broken if you are user-level code, since they
  28.    *    can add new events and not tell you, stepping on your
  29.    *    event numbers) so it appears that is the "right" way
  30.    *    to create new event codes, but you can't access it. 
  31.    *    Had they been the least bit clever, they would have
  32.    *    realized that a static method called "firstUserCodeNumber"
  33.    *    would be the thing to do, preserving backward
  34.    *    compatibility and letting users do clever things.
  35.    *    Stupid, stupid, stupid.<p>
  36.    */
  37.   static final int ANIMATION_EVENT= 1000 + 10;
  38.  
  39.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  40.  
  41.   /**
  42.    * This is one of the three queues for use with this agent. The "unknown" 
  43.    * queue is for transitions whose start or end times are as yet unknown.
  44.    * The "pending" queue is for transitions which have known start and
  45.    * end times, but are not yet due to run. The "running" queue is for
  46.    * the transitions that are currently executing.
  47.    */
  48.   protected Vector unknown;
  49.  
  50.   /**
  51.    * This is one of the three queues for use with this agent. The "unknown" 
  52.    * queue is for transitions whose start or end times are as yet unknown.
  53.    * The "pending" queue is for transitions which have known start and
  54.    * end times, but are not yet due to run. The "running" queue is for
  55.    * the transitions that are currently executing.
  56.    */
  57.   protected Vector pending;
  58.  
  59.   /**
  60.    * This is one of the three queues for use with this agent. The "unknown" 
  61.    * queue is for transitions whose start or end times are as yet unknown.
  62.    * The "pending" queue is for transitions which have known start and
  63.    * end times, but are not yet due to run. The "running" queue is for
  64.    * the transitions that are currently executing.
  65.    */
  66.   protected Vector running;
  67.  
  68.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  69.  
  70.   /**
  71.    * Initialize this agent. This is done automatically, users should 
  72.    * not have to construct this object.
  73.    */
  74.   public animation_agent() {
  75.     /* create the queues */
  76.     unknown=new Vector();
  77.     pending=new Vector();
  78.     running=new Vector();
  79.  
  80.     /* we don't need ticks at first */
  81.     anim_generator.set_need_ticks(false);
  82.   }
  83.  
  84.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  85.  
  86.   /**
  87.    * Handle an animation event.  These periodically get put in the event 
  88.    * "queue" by the animation agent and picked up here.<p>
  89.    *
  90.    * @param event evt the event to dispatch 
  91.    * @param Object user_info the user information passed to the agent when the 
  92.    *                         user object joined the focus set
  93.    * @param interactor to_obj the object to dispatch to 
  94.    * @param int seq_num the sequence number of this event
  95.    * @return boolean true if one of our animatable objects handled the event
  96.    */
  97.   public boolean dispatch_event(event evt,Object user_info,interactor to_obj, 
  98.                 int seq_num) {
  99.  
  100.     boolean work_to_do=true;
  101.     long now=((Long)evt.arg()).longValue();
  102.     int i;
  103.     transition t;
  104.  
  105.     /* while there is more to do */
  106.     while (work_to_do) {
  107.  
  108.       /* reset flag, it becomes true if we move someone to the active list */
  109.       work_to_do=false;
  110.  
  111.       /* is there anyone on the pending list that is now eligible to run */
  112.       for (i=0; i<pending.size(); ++i) {
  113.  
  114.     /* if this guy is now eligible, start him */
  115.     t=(transition)pending.elementAt(i);
  116.     if (t.interval().start_time()<=now) {
  117.  
  118.       /* he's eligible, start him and put him on the active list*/
  119.       t.start(evt,user_info);
  120.       pending.removeElement(t);
  121.  
  122.       /* this list is not sorted */
  123.       running.addElement(t);
  124.  
  125.       /* if there are people on the unknown list that are dependent on
  126.          this guy starting, we now want to move them to the pending
  127.          list */
  128.       work_to_do=dependent_on(time_interval.AFTER_START_OF,t,now);
  129.  
  130.       /* if work to do is now true, we'll need to just restart this
  131.          whole iteration through, since the pending list changed*/
  132.       if (work_to_do) {
  133.         break;
  134.       }
  135.  
  136.       /* we just fall through to the next item on the pending list */
  137.     } else {
  138.       /* since this list is sorted, we can break out as soon as we 
  139.          find a miss */
  140.       break;
  141.     }
  142.       }
  143.     }
  144.  
  145.     /* at this point everybody who is eligible to run on this tick is on the
  146.        running list ... that list is not sorted and we'll need to ping 
  147.        everybody on it, so we just traverse it*/
  148.     for (i=0; i<running.size(); ++i) {
  149.  
  150.       t=(transition)running.elementAt(i);
  151.  
  152.       /* send the message */
  153.       t.step(evt,user_info,now);
  154.  
  155.       /* is he done? */
  156.       if (t.finished()) {
  157.  
  158.     /* ok, he's done... anybody waiting on that trans to end? */
  159.     dependent_on(time_interval.AFTER_END_OF,t,now);
  160.  
  161.     /* Possible problem: If someone is waiting on the end of that
  162.        transition and their start time is 0 msec after it, we
  163.        will wait until the next "tick" before we see them in
  164.        the pending list and they get moved to the running list.
  165.        At some level, this seems ok since they logically "follow"
  166.        the redraw of the end of that transition. */
  167.     /* now send it the "end" transition */
  168.     t.end(evt,user_info);
  169.  
  170.     /* get it out of the run queue */
  171.     running.removeElement(t);
  172.       }
  173.     }
  174.  
  175.     /* do we turn the generator off ? */
  176.     if ((unknown.size()==0) && 
  177.     (pending.size()==0) &&
  178.     (running.size()==0)) {
  179.       /* tell the generator we don't need it */
  180.       anim_generator.set_need_ticks(false);
  181.     }
  182.  
  183.     /* there are probably no other animation agents, but just in case we
  184.      *  let this event go on to them... */
  185.     return false;
  186.   }
  187.  
  188.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  189.  
  190.   /**
  191.    * Is this event one we care about (an ANIMATION_EVENT)?
  192.    * @param event evt the event to test
  193.    * @return boolean true if we are interested in this event
  194.    */
  195.   public boolean event_is_useful(event evt) {
  196.     return (evt.id()==ANIMATION_EVENT);
  197.   }
  198.  
  199.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  200.  
  201.   /**
  202.    * Schedule a transition on behalf of some interactor.<P>
  203.    *
  204.    * This is the principal API for user level code to use to schedule
  205.    * animations. You should pass the transition to this function and the 
  206.    * agent will set things up for you.<p>
  207.    * 
  208.    * @param transition t the transition you want executed (this contains a 
  209.    *                     reference to the animatable object in the transition)
  210.    */
  211.   public void schedule_transition(transition t) {
  212.  
  213.     /* tell the generator we need ticks...  */
  214.     anim_generator.set_need_ticks(true);
  215.  
  216.     /* check to see if it is already valid */
  217.     if (t.interval().valid()) {
  218.       insert_into_pending(t);
  219.     } else {
  220.  
  221.       /* might have specified the start time and put a duration */
  222.       if (t.interval().specified_start() && t.interval().used_duration()) {
  223.     t.interval().set_ending_time(t.interval().start_time() + 
  224.                      t.interval().duration());
  225.  
  226.     /* its now ready */
  227.     insert_into_pending(t);
  228.  
  229.       } else {
  230.  
  231.     /* put it in the unknown list, its not ready yet... must be related to
  232.      some other object... sanity check first*/
  233.     if (t.interval().relative_to_others()==false) {
  234.       throw new sub_arctic_error("Insufficiently specified transition "+
  235.                      "rejected by animation_agent!");
  236.     } else {
  237.       /* its ok */
  238.       unknown.addElement(t);
  239.     }
  240.       }
  241.     }
  242.   }
  243.  
  244.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  245.  
  246.   /**
  247.    * This method puts a new transition in the pending list. This list is
  248.    * ordered by start time.
  249.    *  
  250.    * @param transition t the transition to insert
  251.    */
  252.   protected void insert_into_pending(transition t) {
  253.     int i;
  254.     transition tmp;
  255.  
  256.     /* loop over the pending vector */
  257.     for (i=0; i<pending.size(); ++i) {
  258.       tmp=(transition)pending.elementAt(i);
  259.  
  260.       /* if its less than the one we are looking at ...*/
  261.       if (t.interval().start_time()<tmp.interval().start_time()) {
  262.  
  263.     /* insert in that elements spot */
  264.     pending.insertElementAt(t,i);
  265.  
  266.     /* we're done */
  267.     return;
  268.       }
  269.     }
  270.  
  271.     /* if we are here, then it is larger than everything on the list */
  272.     /* so add at the end */
  273.     pending.addElement(t);
  274.   }
  275.  
  276.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  277.  
  278.   /**
  279.    * This method moves things from the unknown list to the pending list.
  280.    * As it does it, it fills in the values that might be necessary for this
  281.    * object to be fully ready. 
  282.    *  
  283.    * @param int which should be one of time_interval.AFTER_START_OF and 
  284.    *                  time_interval.AFTER_END_OF
  285.    * @param transition target the candidate transition for being depended upon
  286.    * @param long now what time is it
  287.    * @return boolean true if someone was dependent on the target transition
  288.    */
  289.   boolean dependent_on(int which,transition target,long now) {
  290.     int i;
  291.     boolean returnvalue=false;
  292.     transition tmp;
  293.     time_interval interval; 
  294.  
  295.     /* loop over the list of objects which are not yet rich are not yet ready */
  296.     for (i=0; i<unknown.size(); ++i) {
  297.  
  298.       /* get the ith element */
  299.       tmp=(transition)unknown.elementAt(i);
  300.  
  301.       /* get its interval */
  302.       interval=tmp.interval();
  303.  
  304.       /* if its related to this object by the which we need to move it */
  305.       if ((interval.related_to()==target) &&
  306.       (interval.related_how()==which)) {
  307.  
  308.     /* remove it from the list of unknowns */
  309.     unknown.removeElement(tmp);
  310.  
  311.     /* fill in the values */
  312.     interval.set_start_time(now+(interval.delay()));
  313.  
  314.     /* they may have used a duration, if so decode it now */
  315.     if (interval.used_duration()) {
  316.       interval.set_ending_time(interval.start_time() + 
  317.                    interval.duration());
  318.     }
  319.  
  320.     /* ok, its now a valid entry */
  321.     if (!interval.valid()) {
  322.       throw new sub_arctic_error("Invalid time interval constructed:"+
  323.                      "You probably forget to supply an "+
  324.                      "ending time or a duration"); 
  325.     }
  326.  
  327.     /* put the whole transition in the list */
  328.     insert_into_pending(tmp);
  329.  
  330.     /* we have now added something to the pending list, so we 
  331.        need to inform the caller */
  332.     returnvalue=true;
  333.       }
  334.     }
  335.     return returnvalue;
  336.   }
  337.  
  338.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  339.  
  340.   /**
  341.    * This function causes the animation agent to terminate a transition.
  342.    * A transition may be terminated even before it has begun. If you
  343.    * terminate a running transition, other transitions which are 
  344.    * dependent on it ending are triggered. If you terminate a transition
  345.    * which has not yet begun, other pending transitions which are
  346.    * dependent on this transition starting or ending are NOT triggered.
  347.    * Attempting to remove a transition which is neither pending
  348.    * nor running has no effect.  Currently, this does not result
  349.    * in call to the end_transition method of your animatable object.
  350.    * The reason it current doesn't do this is to make sure
  351.    * that people who are just using the end_transition message
  352.    * as a trigger for time-based events do not receive this call.
  353.    * 
  354.    * @param transition target the transition you want removed.
  355.    */
  356.   public void remove_transition(transition target) {
  357.     int i;
  358.     transition t;
  359.  
  360.     /* walk down the running list */
  361.     for (i=0; i<running.size(); ++i) {
  362.  
  363.       t=(transition)running.elementAt(i);
  364.  
  365.       /* is it there? */
  366.       if (t.equals(target)) {
  367.  
  368.     /* found it */
  369.     running.removeElementAt(i);
  370.  
  371.     /* possible modifications of the pending list */
  372.     dependent_on(time_interval.AFTER_END_OF,t,time_interval.now());
  373.  
  374.     /* we are done */
  375.     return;
  376.       }
  377.     }
  378.  
  379.     /* walk down the pending list */
  380.     for (i=0; i<pending.size(); ++i) {
  381.  
  382.       t=(transition)pending.elementAt(i);
  383.  
  384.       /* is it there? */
  385.       if (t.equals(target)) {
  386.     pending.removeElementAt(i);
  387.       }
  388.     }
  389.  
  390.     /* walk down the unknown list */
  391.     for (i=0; i<unknown.size(); ++i) {
  392.  
  393.       t=(transition)unknown.elementAt(i);
  394.  
  395.       /* is it there? */
  396.       if (t.equals(target)) {
  397.     unknown.removeElementAt(i);
  398.       }
  399.     }
  400.     /* we're done */
  401.   }
  402.  
  403.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  404.  
  405. }
  406. /*=========================== COPYRIGHT NOTICE ===========================
  407.  
  408. This file is part of the subArctic user interface toolkit.
  409.  
  410. Copyright (c) 1996 Scott Hudson and Ian Smith
  411. All rights reserved.
  412.  
  413. The subArctic system is freely available for most uses under the terms
  414. and conditions described in 
  415.   http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic/doc/usage.html 
  416. and appearing in full in the lib/interactor.java source file.
  417.  
  418. The current release and additional information about this software can be 
  419. found starting at: http://www.cc.gatech.edu/gvu/ui/sub_arctic/
  420.  
  421. ========================================================================*/
  422.